1   /*
2    * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4    *
5    * This code is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU General Public License version 2 only, as
7    * published by the Free Software Foundation.  Oracle designates this
8    * particular file as subject to the "Classpath" exception as provided
9    * by Oracle in the LICENSE file that accompanied this code.
10   *
11   * This code is distributed in the hope that it will be useful, but WITHOUT
12   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14   * version 2 for more details (a copy is included in the LICENSE file that
15   * accompanied this code).
16   *
17   * You should have received a copy of the GNU General Public License version
18   * 2 along with this work; if not, write to the Free Software Foundation,
19   * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20   *
21   * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22   * or visit www.oracle.com if you need additional information or have any
23   * questions.
24   */
25  
26  package com.sun.java.swing;
27  
28  import sun.awt.EventQueueDelegate;
29  import sun.awt.AppContext;
30  import java.util.Collections;
31  import java.util.Map;
32  import java.util.WeakHashMap;
33  import java.util.concurrent.Callable;
34  import java.applet.Applet;
35  import java.awt.AWTEvent;
36  import java.awt.EventQueue;
37  import java.awt.Component;
38  import java.awt.Container;
39  import java.awt.Window;
40  import javax.swing.JComponent;
41  import javax.swing.RepaintManager;
42  
43  /**
44   * A collection of utility methods for Swing.
45   * <p>
46   * <b>WARNING:</b> While this class is public, it should not be treated as
47   * public API and its API may change in incompatable ways between dot dot
48   * releases and even patch releases. You should not rely on this class even
49   * existing.
50   *
51   * This is a second part of sun.swing.SwingUtilities2. It is required
52   * to provide services for JavaFX applets.
53   *
54   */
55  public class SwingUtilities3 {
56      /**
57       * The {@code clientProperty} key for delegate {@code RepaintManager}
58       */
59      private static final Object DELEGATE_REPAINT_MANAGER_KEY =
60          new StringBuilder("DelegateRepaintManagerKey");
61  
62      /**
63        * Registers delegate RepaintManager for {@code JComponent}.
64        */
65      public static void setDelegateRepaintManager(JComponent component,
66                                                  RepaintManager repaintManager) {
67          /* setting up flag in AppContext to speed up lookups in case
68           * there are no delegate RepaintManagers used.
69           */
70          AppContext.getAppContext().put(DELEGATE_REPAINT_MANAGER_KEY,
71                                         Boolean.TRUE);
72  
73          component.putClientProperty(DELEGATE_REPAINT_MANAGER_KEY,
74                                      repaintManager);
75      }
76  
77      private static final Map<Container, Boolean> vsyncedMap =
78          Collections.synchronizedMap(new WeakHashMap<Container, Boolean>());
79  
80      /**
81       * Sets vsyncRequested state for the {@code rootContainer}.  If
82       * {@code isRequested} is {@code true} then vsynced
83       * {@code BufferStrategy} is enabled for this {@code rootContainer}.
84       *
85       * Note: requesting vsynced painting does not guarantee one. The outcome
86       * depends on current RepaintManager's RepaintManager.PaintManager
87       * and on the capabilities of the graphics hardware/software and what not.
88       *
89       * @param rootContainer topmost container. Should be either {@code Window}
90       *  or {@code Applet}
91       * @param isRequested the value to set vsyncRequested state to
92       */
93      public static void setVsyncRequested(Container rootContainer,
94                                           boolean isRequested) {
95          assert (rootContainer instanceof Applet) || (rootContainer instanceof Window);
96          if (isRequested) {
97              vsyncedMap.put(rootContainer, Boolean.TRUE);
98          } else {
99              vsyncedMap.remove(rootContainer);
100         }
101     }
102 
103     /**
104      * Checks if vsync painting is requested for {@code rootContainer}
105      *
106      * @param rootContainer topmost container. Should be either Window or Applet
107      * @return {@code true} if vsync painting is requested for {@code rootContainer}
108      */
109     public static boolean isVsyncRequested(Container rootContainer) {
110         assert (rootContainer instanceof Applet) || (rootContainer instanceof Window);
111         return Boolean.TRUE == vsyncedMap.get(rootContainer);
112     }
113 
114     /**
115      * Returns delegate {@code RepaintManager} for {@code component} hierarchy.
116      */
117     public static RepaintManager getDelegateRepaintManager(Component
118                                                             component) {
119         RepaintManager delegate = null;
120         if (Boolean.TRUE == AppContext.getAppContext().get(
121                                                DELEGATE_REPAINT_MANAGER_KEY)) {
122             while (delegate == null && component != null) {
123                 while (component != null
124                          && ! (component instanceof JComponent)) {
125                     component = component.getParent();
126                 }
127                 if (component != null) {
128                     delegate = (RepaintManager)
129                         ((JComponent) component)
130                           .getClientProperty(DELEGATE_REPAINT_MANAGER_KEY);
131                     component = component.getParent();
132                 }
133 
134             }
135         }
136         return delegate;
137     }
138 
139     /*
140      * We use maps to avoid reflection. Hopefully it should perform better
141      * this way.
142      */
143     public static void setEventQueueDelegate(
144             Map<String, Map<String, Object>> map) {
145         EventQueueDelegate.setDelegate(new EventQueueDelegateFromMap(map));
146     }
147 
148     private static class EventQueueDelegateFromMap
149     implements EventQueueDelegate.Delegate {
150         private final AWTEvent[] afterDispatchEventArgument;
151         private final Object[] afterDispatchHandleArgument;
152         private final Callable<Void> afterDispatchCallable;
153 
154         private final AWTEvent[] beforeDispatchEventArgument;
155         private final Callable<Object> beforeDispatchCallable;
156 
157         private final EventQueue[] getNextEventEventQueueArgument;
158         private final Callable<AWTEvent> getNextEventCallable;
159 
160         @SuppressWarnings("unchecked")
161         public EventQueueDelegateFromMap(Map<String, Map<String, Object>> objectMap) {
162             Map<String, Object> methodMap = objectMap.get("afterDispatch");
163             afterDispatchEventArgument = (AWTEvent[]) methodMap.get("event");
164             afterDispatchHandleArgument = (Object[]) methodMap.get("handle");
165             afterDispatchCallable = (Callable<Void>) methodMap.get("method");
166 
167             methodMap = objectMap.get("beforeDispatch");
168             beforeDispatchEventArgument = (AWTEvent[]) methodMap.get("event");
169             beforeDispatchCallable = (Callable<Object>) methodMap.get("method");
170 
171             methodMap = objectMap.get("getNextEvent");
172             getNextEventEventQueueArgument =
173                 (EventQueue[]) methodMap.get("eventQueue");
174             getNextEventCallable = (Callable<AWTEvent>) methodMap.get("method");
175         }
176 
177         @Override
178         public void afterDispatch(AWTEvent event, Object handle) throws InterruptedException {
179             afterDispatchEventArgument[0] = event;
180             afterDispatchHandleArgument[0] = handle;
181             try {
182                 afterDispatchCallable.call();
183             } catch (InterruptedException e) {
184                 throw e;
185             } catch (RuntimeException e) {
186                 throw e;
187             } catch (Exception e) {
188                 throw new RuntimeException(e);
189             }
190         }
191 
192         @Override
193         public Object beforeDispatch(AWTEvent event) throws InterruptedException {
194             beforeDispatchEventArgument[0] = event;
195             try {
196                 return beforeDispatchCallable.call();
197             } catch (InterruptedException e) {
198                 throw e;
199             } catch (RuntimeException e) {
200                 throw e;
201             } catch (Exception e) {
202                 throw new RuntimeException(e);
203             }
204         }
205 
206         @Override
207         public AWTEvent getNextEvent(EventQueue eventQueue) throws InterruptedException {
208             getNextEventEventQueueArgument[0] = eventQueue;
209             try {
210                 return getNextEventCallable.call();
211             } catch (InterruptedException e) {
212                 throw e;
213             } catch (RuntimeException e) {
214                 throw e;
215             } catch (Exception e) {
216                 throw new RuntimeException(e);
217             }
218         }
219     }
220 }